#include "StringTabV0.h"
#include <assert.h>
#include <stdio.h>
#include <cstdlib>
#include <ctype.h>


size_t const StringTabNode::INIT_SIZE = 1024 * 1024 * 10;//10mb
size_t       StringTabNode::current_size = StringTabNode::INIT_SIZE;

StringTabNode::StringTabNode() :
    data(new char[current_size]),
    next(NULL)
{
}

char* StringTabNode::getData()
{
    return data;
}

void StringTabNode::setNext(StringTabNode* next)
{
    this->next = next;
}

StringTabNode::~StringTabNode()
{
    //data will be deleted by StringTab
    //delete[] next;//recursive delete all other nodes
}

StringTabV0::StringTabV0() :
    firstNode(new StringTabNode()),
    currentNode(firstNode),
    head(firstNode->getData()),
    last_head(0),
    tail(head),
    free(StringTabNode::current_size),
    len(0),
    last_len(0)
{
    last_head = head;
}

StringTabV0::~StringTabV0(void)
{
    delete firstNode;//deletes all further nodes
}

void StringTabV0::putChar(char c)
{
    if(free == 0)
    {
        //realloc
        realloc();
    }

    //copy char and move pointer further
    *tail = tolower(c);
    tail++;
    len++;
    free--;
}

Lexem StringTabV0::mkLexem()
{
    putChar('\0');

    //create lexem
    Lexem t(head, len);

    last_head = head;//for revertLastLexem()
    last_len  = len;//for revertLastLexem()
    //prepare for further lexems = make lexem final
    head = tail;
    len  = 0;
    
    return t;
}

void StringTabV0::revertLastLexem()
{
    assert(head != last_head);//this operation is possible one time
    tail  = head = last_head;//reset
    free += last_len;//increase free space
}

void StringTabV0::realloc()
{
    StringTabNode* newNode = new StringTabNode();
    assert(newNode != NULL);
    currentNode->setNext(newNode);

    //move partially inserted lexem into new node
    size_t signsToMove = tail - head;
    memmove(newNode->getData(), head, signsToMove);

    //calc free mem and insert position of further lexems
    free = StringTabNode::current_size - signsToMove;
    tail = newNode->getData()          + signsToMove;
    last_head = head;//for revertLastLexem()
    head = newNode->getData();
    //len is unchanged
    if(free < len){
        StringTabNode::current_size *= 2;
        delete newNode;
        newNode = NULL;
        printf("###WARNING### lexem \"%s\"!\n", head);
        printf("###WARNING### is to long, increasing maximal length!\n");
        realloc();//retry with double size
    } 
}
